package cn.edu.hitsz.compiler.parser;

import cn.edu.hitsz.compiler.NotImplementedException;
import cn.edu.hitsz.compiler.lexer.Token;
import cn.edu.hitsz.compiler.parser.table.NonTerminal;
import cn.edu.hitsz.compiler.parser.table.Production;
import cn.edu.hitsz.compiler.parser.table.Status;
import cn.edu.hitsz.compiler.parser.table.Term;
import cn.edu.hitsz.compiler.symtab.SourceCodeType;
import cn.edu.hitsz.compiler.symtab.SymbolTable;
import cn.edu.hitsz.compiler.symtab.SymbolTableEntry;

import java.util.*;

// TODO: 实验三: 实现语义分析
public class SemanticAnalyzer implements ActionObserver {

    private class Node
    {
        private Token token;
        private SourceCodeType type;

        public Node()
        {
            token = null;
            type = null;
        }
        public Node(Token token)
        {
            this.token= token;
            type = null;
        }
        public void setType(SourceCodeType type)
        {
            if (this.type == null)
            {
                this.type = type;
            }
        }
    }
    SymbolTable symbolTable;

    List<Node> stack = new ArrayList<>();
    @Override
    public void whenAccept(Status currentStatus) {
        //do nothing
    }

    @Override
    public void whenReduce(Status currentStatus, Production production)
    {
        Node node = new Node();
        switch (production.index())
        {
            case 4:// S -> D id
            {
                Node temp = stack.get(stack.size() - 1);
                temp.setType(stack.get(stack.size() - 2).type);
                if (temp.token != null) {
                    symbolTable.addType(temp.token.getText(), temp.type);
                }
                break;
            }
            case 5:// D -> int
            {
                node.setType(SourceCodeType.Int);
                break;
            }
            case 6:// S -> id = E
            {
                Node id = stack.get(stack.size()-3);
                if (symbolTable.get(id.token.getText()).getType() == null)
                {
                    throw new RuntimeException("未定义变量" + id.token.getText());
                }
                break;
            }
            case 14:// B -> id
            {
                Node id = stack.get(stack.size()-1);
                if (symbolTable.get(id.token.getText()).getType() == null)
                {
                    throw new RuntimeException("未定义变量" + id.token.getText());
                }
                break;
            }
            default:
                break;
        }
        List<String> bodyStr = Arrays.stream(production.toString().split(" ")).toList();
        for(int i=0;i<bodyStr.size()-2;i++)
        {
            stack.remove(stack.size()-1);
        }
        stack.add(node);
    }

    @Override
    public void whenShift(Status currentStatus, Token currentToken) {
        stack.add(new Node(currentToken));
    }

    @Override
    public void setSymbolTable(SymbolTable table) {
        symbolTable = table;
    }
}

